package com.game.service.game.redblack;

import com.game.service.app.Deduction;
import com.game.service.app.FeeOrderReturn;
import com.game.service.app.Utils;
import com.game.service.app.get_score.JsonBean;
import com.game.service.app.get_score.UserLoginInfo;
import com.game.service.app.match.GetMatchEvent;
import com.game.service.app.match.MatchEvent;
import com.game.service.beans.UserInfo;
import com.game.service.comm.AESUtils;
import com.game.service.comm.EncipheredData;
import com.game.service.db.UserScoreDaoImpl;
import com.game.service.game.redblack.match.ArrowOrder;
import com.game.service.game.redblack.match.MatchScoreRanking;
import com.game.service.game.redblack.match.MatchUser;
import com.game.service.game.redblack.match.PostJsonMatch;
import com.game.service.game.turntable.GameResult;
import com.game.service.game.turntable.PrizeItem;
import com.game.service.game.turntable.UserBet;
import com.game.service.socket.CountdownTimer;
import com.game.service.socket.FileUtils;
import com.game.service.socket.SocketServer;
import com.game.service.windows.LogWindows;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.java_websocket.WebSocket;

import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.game.service.app.Score.*;
import static com.game.service.app.Utils.LogDate;
import static com.game.service.app.Utils.random;
import static com.game.service.define.GameDefine.*;
import static com.game.service.define.RoomConfig.*;

public class RedBlackMatch {

    private final ConcurrentHashMap<Integer, UserInfo> userMap = new ConcurrentHashMap<>();//比赛房间的玩家信息，登录保存，并且初始化玩家的分数为10000点
    static RedBlackMatch mRedBlackMatch;
    private MatchEvent matchEvent = new MatchEvent();
    private int orderIdIndex = 10000000;
    private int runTime = 0;
    ExecutorService executor = Executors.newSingleThreadExecutor();
    ArrayList<MatchScoreRanking> recordGames = new ArrayList<>();

    public static synchronized RedBlackMatch getInstance() {
        if (mRedBlackMatch == null) {
            mRedBlackMatch = new RedBlackMatch();
            mRedBlackMatch.matchEvent.reset();//重置
            mRedBlackMatch.onGameRun();

        }
        return mRedBlackMatch;
    }

    /**
     * 服务器开启成功后运行游戏线程
     */
    public void onGameRun() {

        CountdownTimer countdown = new CountdownTimer(); //
        TimerTask task = new TimerTask() {

            public void run() {

                try {
                    MyGameRun();
                } catch (Exception e) {
                    String error = "GameRun()" + e + "\n" + Arrays.toString(e.getStackTrace());
                    FileUtils.writeTxtToFile(error, LogDate(), LOG_NAME_ERROR);
                    LogWindows.getLogWindows().printToTextArea(error, RedBlackMatch.class);
                }

            }

            private void MyGameRun() {

                if (runTime % 60 == 0) {//每分钟更新一次游戏比赛排行
                    postArrowMatchRanking(false);
                    getArrowMatchConfig();
                }
                if (MatchIsOver()) {
                    postArrowMatchRanking(true);
                    //清除房间信息
                    userMap.clear();
                }
                runTime++;
            }
        };
        countdown.startTimer(task);
    }

    public void addMatchUser(WebSocket conn, UserInfo userInfo) {
        int matchEventID = matchEvent.getEvent_id();
        if (matchEventID == -1) {
            JsonBean<String> cmd = new JsonBean<>();
            cmd.code = GAME_MATCH_OVER;
            cmd.msg = "The limited-time event has not started or has ended.";
            SocketServer.getKernel().sendErrorMsg(conn, cmd);
            return;
        }
        UserLoginInfo loginInfo = new UserLoginInfo();
        int uid = userInfo.getUid();
        //获取数据库的本场比赛游戏分数
        MatchUser matchUser = UserScoreDaoImpl.getInstance().getMatchUser(matchEventID, GAME_ID, uid);

        String json = new Gson().toJson(userInfo);
        UserInfo userMatchInfo = new Gson().fromJson(json, UserInfo.class);

        if (matchUser == null) {
            userMatchInfo.setScore(matchEvent.getInitial_score());//初始化玩家免费分数
            userMatchInfo.setPlayCounts(0);//初始化玩家游戏次数,默认为0
            UserScoreDaoImpl.getInstance().addMatchUser(matchEventID, GAME_ID, userMatchInfo);
            loginInfo.setScore(userMatchInfo.getScore());
        } else {
            userMatchInfo.setScore(matchUser.getuScore());//加载数据库的分数
            userMatchInfo.setPlayCounts(matchUser.getMatch_limit());//加载数据库的剩余游戏次数
            loginInfo.setScore(matchUser.getuScore());//获取数据库的分数
        }
        //查询排行榜里是否保存当前登录用户信息,如果没有则添加
        sendMatchScoreRanking(conn, userMatchInfo, loginInfo);

        userMap.put(uid, userMatchInfo);
        SocketServer.getKernel().send(conn, GAME_MAIN, GAME_C_SUB_ENTER_ROOM_RETURN, loginInfo);

    }

    private void sendMatchScoreRanking(WebSocket conn, UserInfo userInfo, UserLoginInfo loginInfo) {
        MatchScoreRanking rankingNew = null;
        for (MatchScoreRanking ranking : recordGames) {
            if (ranking.getUid() == userInfo.getUid()) {
                rankingNew = ranking;
            }
        }
        if (rankingNew == null) {//没有则添加到内存数组里面
            rankingNew = new MatchScoreRanking();
            rankingNew.setUid(userInfo.getUid());
            rankingNew.setName(loginInfo.getUser_nickname());
            rankingNew.setScorePoints((int) loginInfo.getScore());
            rankingNew.setMatch_limit(userInfo.getPlayCounts());
            recordGames.add(rankingNew);
        }
        sendRankingSelf(conn, userInfo.getUid(), recordGames);//
    }

    public void betMatch(WebSocket conn, UserBet userBet) {
        int matchEventID = matchEvent.getEvent_id();
        if (matchEventID == -1) {
            JsonBean<String> cmd = new JsonBean<>();
            cmd.code = GAME_MATCH_OVER;
            cmd.msg = "The limited-time event has not started or has ended.";
            SocketServer.getKernel().sendErrorMsg(conn, cmd);
            return;
        }
        UserInfo userMatch = userMap.get(userBet.getUid());
        if (userMatch == null) {
            return;
        }
        //增加判断,对局数>设置的最大数
        int playCounts = userMatch.getPlayCounts();
        if (playCounts >= matchEvent.getMatch_limit()) {
            JsonBean<String> cmd = new JsonBean<>();
            cmd.code = GAME_MATCH_OVER;
            cmd.msg = "You have completed the game rounds and are waiting for the event settlement.";
            SocketServer.getKernel().sendErrorMsg(conn, cmd);
            return;
        }
        long score = userMatch.getScore();//比赛系统中玩家的分数
        FeeOrderReturn feeOrderReturn = new FeeOrderReturn();// 模拟返回
        feeOrderReturn.setScore(score);
        Deduction deduction = new Deduction();
        feeOrderReturn.setDeduction(deduction);

        final String orderid = userBet.getOrderIdPrize();
        GameResult gameResult = onTurntableGameResult(orderid, feeOrderReturn, userBet, userMatch);
        score += gameResult.prize;//本次获得的分数
        userMatch.setScore(score);
        //处理游戏结果
        executor.submit(() -> UserScoreDaoImpl.getInstance().updateMatchUser(matchEventID, GAME_ID, userMatch));
        System.out.println(gameResult);
        postArrowMatchPlaying(userMatch.getUid(), gameResult, true);//实时发送
        SocketServer.getKernel().send(conn, GAME_MAIN, GAME_C_SUB_BET_RETURN, gameResult);
        //
        for (MatchScoreRanking ranking : recordGames) {
            if (userMatch.getUid() == ranking.getUid()) {//下注后更新自己的分数
                ranking.setScorePoints((int) score);
                ranking.setMatch_limit(userMatch.getPlayCounts());//更新游玩次数
            }
        }
        sendRankingSelf(conn, userMatch.getUid(), recordGames);//发送自己的分数以及排名


    }

    private void sendRankingSelf(WebSocket conn, int uid, ArrayList<MatchScoreRanking> recordGames) {
        recordGames.sort(Comparator.comparingInt(MatchScoreRanking::getScorePoints));//
        Collections.reverse(recordGames);//倒序
        int rankingId = 1;
        for (MatchScoreRanking ranking : recordGames) {
            ranking.setRankingId(rankingId++);
        }
        MatchScoreRanking rankingSelf = null;
        for (MatchScoreRanking ranking : recordGames) {
            if (uid == ranking.getUid()) {
                rankingSelf = ranking;
                break;
            }
        }

        if (rankingSelf != null) {
            rankingSelf.setMatch_limit_config(matchEvent.getMatch_limit());
        }

        SocketServer.getKernel().send(conn, GAME_MAIN, GAME_C_SUB_MATCH_RANKING_SELF_RETURN, rankingSelf);

    }

    public void getMatchRanking(WebSocket conn) {

        int matchEventID = matchEvent.getEvent_id();
        if (matchEventID == -1) {
            JsonBean<String> cmd = new JsonBean<>();
            cmd.code = GAME_MATCH_OVER;
            cmd.msg = "The limited-time event has not started or has ended.";
            SocketServer.getKernel().sendErrorMsg(conn, cmd);
            return;
        }
        new Thread(() -> {
            // 发送 比赛排行榜
            recordGames = matchRecordGames();//从数据库拿取数据排序
            SocketServer.getKernel().send(conn, GAME_MAIN, GAME_C_SUB_MATCH_RANKING_RETURN, recordGames);
        }).start();

    }

    public void postArrowMatchRanking(boolean isSave) {
        int matchEventID = matchEvent.getEvent_id();
        if (matchEventID == -1) {
            return;
        }
        new Thread(() -> {
            String orderId = orderIdHead() + orderIdIndex;
            recordGames = matchRecordGames();//从数据库拿取数据排序
            String plainText = ArrowOrder.createMatchRankingJson(orderId, matchEventID, recordGames, isSave);
            if (isSave) {
                matchEvent.reset();//游戏结束后，重置
            }
            EncipheredData encipheredData = AESUtils.createEncipheredData(plainText);
            String json = new Gson().toJson(encipheredData);
            PostJsonMatch match = new PostJsonMatch();
            match.post(json, API_POST_MATCH_RANKING, PostJsonMatch.POST_TYPE_RANKING, orderId, ADMIN_ID, isSave);


        }).start();
    }


    public void postArrowMatchPlaying(int uid, GameResult gameResult, boolean isSave) {
        int matchEventID = matchEvent.getEvent_id();
        if (matchEventID == -1) {
            return;
        }
        String orderId = orderIdHead() + orderIdIndex;
        ArrayList<long[]> matchPlayingList = matchPlaying(uid, gameResult);
        String plainText = ArrowOrder.createMatchPayingJson(orderId, matchEventID, matchPlayingList, isSave);
        EncipheredData encipheredData = AESUtils.createEncipheredData(plainText);
        String json = new Gson().toJson(encipheredData);
        PostJsonMatch match = new PostJsonMatch();
        match.post(json, API_POST_MATCH_PLAYING, PostJsonMatch.POST_TYPE_PLAYING, orderId, uid, isSave);
    }


    public ArrayList<long[]> matchPlaying(int uid, GameResult gameResult) {
        ArrayList<long[]> matchPlayingList = new ArrayList<>();
        long[] list = new long[3];
        list[0] = uid;
        list[1] = gameResult.prize - gameResult.fee;
        list[2] = System.currentTimeMillis();
        matchPlayingList.add(list);
        return matchPlayingList;
    }

    public ArrayList<MatchScoreRanking> matchRecordGames() {
        ArrayList<MatchScoreRanking> matchScoreRankings = new ArrayList<>();
        List<MatchUser> matchUserList = UserScoreDaoImpl.getInstance().getMatchUserList(matchEvent.getEvent_id(), GAME_ID);
        for (MatchUser user : matchUserList) {
            MatchScoreRanking ranking = new MatchScoreRanking();
            ranking.setUid(user.getUid());
            ranking.setName(user.getName() == null ? "" : user.getName());
            ranking.setScorePoints(user.getuScore());//计算总得分
            ranking.setMatch_limit(user.getMatch_limit());//加载游戏次数
            matchScoreRankings.add(ranking);
        }
        matchScoreRankings.sort(Comparator.comparingInt(MatchScoreRanking::getScorePoints));//
        Collections.reverse(matchScoreRankings);//倒序
        int rankingId = 1;
        for (MatchScoreRanking ranking : matchScoreRankings) {
            ranking.setRankingId(rankingId++);
        }
        return matchScoreRankings;
    }

    /**
     * 获取总服务器配置信息!!!
     * 使用注意：
     *
     * @apiNote 比赛活动信息, 通常每分钟定时更新，同时结束前3分钟停止更新
     */

    private void getArrowMatchConfig() {
        FileUtils.writeTxtToFile("获取配置,请求地址:" + API_POST_MATCH_RANKING_EVENT, Utils.LogDate(), LOG_NAME_ROOM);
        if (matchEvent.getEvent_id() != -1) {//正常限时活动比赛
            //结束前3分钟不再更新,强制比赛进行,直到结束,且结束后一分钟之内不请求新数据，等待程序自动结算完成再请求新的比赛
            long time = matchEvent.getEnd_time() - System.currentTimeMillis() / 1000;
            if (time > -60 && time < 180) {
                LogWindows.getLogWindows().printToTextArea("停止更新配置,距离比赛还剩:" + time + "秒", RedBlackMatch.class);
                return;
            }
        }
        new Thread(() -> {
            GetMatchEvent event = new GetMatchEvent();
            event.systemID = Utils.encryptMD5("SYSTEM_ID");
            event.gameid = GAME_ID + "";
            String plainText = new Gson().toJson(event);
            EncipheredData eventJson = AESUtils.createEncipheredData(plainText);
            String json = new Gson().toJson(eventJson);
            String result = doPostForm(API_POST_MATCH_RANKING_EVENT, json);

            if (result.isEmpty()) {
                System.out.println("获取配置:失败");
                return;
            }
            Type type0 = new TypeToken<JsonBean<ArrayList<MatchEvent>>>() {
            }.getType();

            JsonBean<ArrayList<MatchEvent>> bean = new Gson().fromJson(result, type0);

            ArrayList<MatchEvent> matchEventArrayList = bean.data;
            // System.out.println("获取比赛配置:" + result);
            String log = "获取比赛配置:" + result;
            LogWindows.getLogWindows().printToTextArea(log, RedBlackMatch.class);
            if (matchEventArrayList != null && !matchEventArrayList.isEmpty()) {
                FileUtils.writeTxtToFile("比赛配置,获取成功:" + matchEventArrayList, Utils.LogDate(), LOG_NAME_ROOM);
                matchEvent = matchEventArrayList.get(0);
            } else {
                matchEvent.reset();//没有重置
            }

        }).start();
    }

    private boolean MatchIsOver() {

        long currentTimeMillis = System.currentTimeMillis();
        long matchEndTimeMillis = matchEvent.getEnd_time() * 1000;
        if (matchEndTimeMillis == 0) {//没有比赛房间
            return true;
        }
        //当前指令时间超过比赛结束时间
        return currentTimeMillis > matchEndTimeMillis;
    }

    /***
     *
     * @return  "game_gameid_时间_比赛id_";
     */
    public String orderIdHead() {
        orderIdIndex++;
        return "game_" + GAME_ID + "_" + Utils.getDateTableId() + "_" + ORDER_MATCH_EVENT + matchEvent.getEvent_id() + "_";
    }

    public static GameResult onTurntableGameResult(String orderid, FeeOrderReturn feeOrderReturn, UserBet userBet, UserInfo userInfo) {
        int[] randomArray = new int[]{Utils.random(1, 6), Utils.random(1, 6), Utils.random(1, 6)};
        //int[] randomArray = new int[]{6, 6, Utils.random(5, 6)};
        userInfo.setPlayCountsAdd();//记录玩家游戏次数
        long score = feeOrderReturn.getScore();
        GameResult gameResult = new GameResult();
        gameResult.orderid = orderid;
        gameResult.score = score;
        gameResult.item =(randomArray[0] ==randomArray[1] &&randomArray[1]==randomArray[2] )?1:0 ;
        gameResult.betid = 0;//新增记录下注id 对应betArray[]
        gameResult.prizeid = 0;//返奖id 对应tableItems[]
        gameResult.ratio = "x";
        gameResult.fee = 0;
        int bonusScore=0;//彩金
        if (gameResult.item == 1) {//豹子给额外的彩金
             bonusScore=  50+(randomArray[0]-1)*10;
        }
        gameResult.prize = randomArray[0] + randomArray[1] + randomArray[2] +bonusScore;
        gameResult.deduction = feeOrderReturn.getDeduction();//本次玩家扣除内容
        gameResult.isRed = userBet.getIsRed();
        gameResult.itemStatus = 0;
        gameResult.randomArray = randomArray;
        userInfo.setScore(score + gameResult.prize);//记录玩家当前分数

        return gameResult;


    }

}
